﻿/* Copyright (C) Siemens AG, 2012. All Rights Reserved.
 * Author: Roland Eckl, Corporate Technology
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

 using System;
using System.Diagnostics;
using System.Runtime.InteropServices;


namespace RVM.Helpers
{
    /// <summary>
    /// Callback signature
    /// </summary>
    /// <param name="hwnd"></param>
    /// <param name="lParam"></param>
    /// <returns></returns>
    public delegate bool CallBack(int hwnd, int lParam);

    /// <summary>
    /// Window States.
    /// </summary>
    public enum WindowState
    {
        SW_HIDE            = 0,
        SW_SHOWNORMAL      = 1,
        SW_NORMAL          = 1,
        SW_SHOWMINIMIZED   = 2,
        SW_SHOWMAXIMIZED   = 3,
        SW_MAXIMIZE        = 3,
        SW_SHOWNOACTIVATE  = 4,
        SW_SHOW            = 5,
        SW_MINIMIZE        = 6,
        SW_SHOWMINNOACTIVE = 7,
        SW_SHOWNA          = 8,
        SW_RESTORE         = 9,
        SW_SHOWDEFAULT     = 10,
        SW_FORCEMINIMIZE   = 11,
        SW_MAX = 11
    }

    /// <summary>
    /// Does things with the console's window (shell)
    /// TODO: Implement SetConsoleTitle through Windows API and replace enumerating over all windows!
    /// </summary>
    public static class ConsoleWindowHelper
    {
        #region Windows API

        /// <summary>
        ///  Enumerates over all windows. 
        /// </summary>
        /// <param name="callback">Delegate called for every window.</param>
        /// <param name="param"></param>
        /// <returns></returns>
        [DllImport("user32.dll")]
        static extern int EnumWindows(CallBack callback, int param);

        /// <summary>
        /// Receives the thread and process id for a given window handle.
        /// </summary>
        /// <param name="hWnd"></param>
        /// <param name="lpdwProcessId"></param>
        /// <returns></returns>
        [DllImport("user32.dll", SetLastError = true)]
        static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);

        /// <summary>
        /// Shows or hides a window.
        /// </summary>
        /// <param name="hwnd">Window Handle</param>
        /// <param name="nCmdShow">Window Message</param>
        /// <returns></returns>
        [DllImport("User32")]
        private static extern int ShowWindow(int hwnd, int nCmdShow);

        #endregion

        #region Private Members

        /// <summary>
        /// Received window handle.
        /// </summary>
        private static int _windowHandle = -1;

        /// <summary>
        /// Own process ID.
        /// </summary>
        private static readonly int _processId = Process.GetCurrentProcess().Id;

        #endregion

        #region Public Members

        /// <summary>
        /// Public accessor for the window handle.
        /// </summary>
        public static int WindowHandle
        {
            get { return _windowHandle; }
        }

        /// <summary>
        /// TRUE, if window handle was found.
        /// </summary>
        public static bool HasWindowHandle
        {
            get { return (_windowHandle > 0); }
        }

        #endregion

        #region Public Methods

        /// <summary>
        /// Shows (or hides) a window.
        /// </summary>
        /// <param name="showOrHide">TRUE, if window has to be shown.</param>
        /// <returns></returns>
        public static bool ShowWindow(bool showOrHide)
        {
            return ShowWindow(showOrHide ? WindowState.SW_RESTORE : WindowState.SW_HIDE);
        }

        /// <summary>
        /// Sets a specific Window State.
        /// </summary>
        /// <param name="state"></param>
        /// <returns></returns>
        public static bool ShowWindow(WindowState state)
        {
            if (HasWindowHandle)
            {
                ShowWindow(_windowHandle, (int)state);
                return true;
            }
            return false;
        }

        /// <summary>
        /// Starts to find the window handle.
        /// </summary>
        public static void FindConsoleWindow()
        {
            CallBack callBack = new CallBack(DisplayWindowInfo);

            // Anfordern, dass das Betriebssystem alle Fenster auflistet und Ihren
            // Rückruf mit dem Handle jedes Fensters auslöst.
            EnumWindows(callBack, 0);
        }

        #endregion

        #region Private Methods

        /// <summary>
        /// Event handler called for every window in the system.
        /// </summary>
        /// <param name="hWnd"></param>
        /// <param name="lParam"></param>
        /// <returns></returns>
        private static bool DisplayWindowInfo(int hWnd, int lParam)
        {

            uint processID = 0;
            uint threadID = GetWindowThreadProcessId(new IntPtr(hWnd), out processID);

            if (_processId == processID)
                _windowHandle = hWnd;
            return true;
        }

        #endregion
    }
}
